package com.zjj.lbw.algorithm.dp;

/**
 * @author zhanglei.zjj
 * @description leetcode_91. 解码方法
 * 一条包含字母A-Z 的消息通过以下映射进行了 编码 ：
 * <p>
 * 'A' -> "1"
 * 'B' -> "2"
 * ...
 * 'Z' -> "26"
 * 要 解码 已编码的消息，所有数字必须基于上述映射的方法，反向映射回字母（可能有多种方法）。例如，"11106" 可以映射为：
 * <p>
 * "AAJF" ，将消息分组为 (1 1 10 6)
 * "KJF" ，将消息分组为 (11 10 6)
 * 注意，消息不能分组为 (1 11 06) ，因为 "06" 不能映射为 "F" ，这是由于 "6" 和 "06" 在映射中并不等价。
 * <p>
 * 给你一个只含数字的 非空 字符串 s ，请计算并返回 解码 方法的 总数 。
 * <p>
 * 题目数据保证答案肯定是一个 32 位 的整数。
 * <p>
 * <p>
 * <p>
 * 示例 1：
 * <p>
 * 输入：s = "12"
 * 输出：2
 * 解释：它可以解码为 "AB"（1 2）或者 "L"（12）。
 * 示例 2：
 * <p>
 * 输入：s = "226"
 * 输出：3
 * 解释：它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。
 * 示例 3：
 * <p>
 * 输入：s = "06"
 * 输出：0
 * 解释："06" 无法映射到 "F" ，因为存在前导零（"6" 和 "06" 并不等价）。
 * <p>
 * <p>
 * 提示：
 * <p>
 * 1 <= s.length <= 100
 * s 只包含数字，并且可能包含前导零。
 * @date 2023/7/7 10:31
 */
public class DecodeWays_leetcode_91 {
    // dp滚动数组实现
    public int numDecodings(String s) {
        // 特殊情况，第一个字符就是'0'
        if (s.startsWith("0")) {
            return 0;
        }

        int n = s.length();
        // 初始值
        int current = 0;
        int pre = 1;
        int prePre = 0;

        for (int i = 1; i <= n; i++) {
            current = 0;
            // 当前字符不是'0'，可以单独映射
            if (s.charAt(i - 1) != '0') {
                current = pre;
            }

            // 当前字符可以和前面一个字符组合映射
            if (i >= 2) {
                int num = (s.charAt(i - 2) - '0') * 10 + s.charAt(i - 1) - '0';
                if (num >= 10 && num <= 26) {
                    current += prePre;
                }
            }
            // 移动指针
            prePre = pre;
            pre = current;
        }
        return current;
    }

    // 标准dp解法
    public int numDecodings1(String s) {
        // 特殊情况，第一个字符就是'0'
        if (s.startsWith("0")) {
            return 0;
        }

        int n = s.length();
        int[] dp = new int[n + 1];
        // 初始值
        dp[0] = 1;
        for (int i = 1; i <= n; i++) {
            // 当前字符不是'0'，可以单独映射
            if (s.charAt(i - 1) != '0') {
                dp[i] = dp[i - 1];
            }

            // 当前字符可以和前面一个字符组合映射
            if (i >= 2) {
                int num = (s.charAt(i - 2) - '0') * 10 + s.charAt(i - 1) - '0';
                if (num >= 10 && num <= 26) {
                    dp[i] += dp[i - 2];
                }
            }
        }

        return dp[n];
    }
}
